interface PromiseWithResolvers<T> {
  promise: Promise<T>
  resolve: (value: T | PromiseLike<T>) => void
  reject: (reason?: any) => void
}

export function withResolvers<T>(): PromiseWithResolvers<T> {
  let resolve: (value: T | PromiseLike<T>) => void;
  let reject: (reason?: any) => void;

  const promise = new Promise<T>((res, rej) => {
    resolve = res;
    reject = rej;
  });

  // 使用类型断言告诉 TypeScript 编译器变量已被赋值
  return {
    promise,
    resolve: resolve!, // 非空断言
    reject: reject! // 非空断言
  };
}

/**
 * 创建一个带有异步超时的 Promise
 * @param {number} delay - 超时延迟时间（以毫秒为单位，默认为0）
 * @returns {Promise<void>} - 返回一个 Promise，在指定延迟后解析
 */
export function asyncTimeout(delay: number = 0): Promise<void> {
  return new Promise(resolve => {
    const timer = setTimeout(() => {
      clearTimeout(timer);
      resolve();
    }, delay);
  });
}

/**
 * 处理 await 异常处理
 * @param promise
 * @param errorExt
 * @returns
 */
export function to<T, U = any>(promise: Promise<T>, errorExt?: Record<string, any>): Promise<[U | null, T | undefined]> {
  return promise
    .then<[null, T]>((data: T) => [null, data])
    .catch<[U, undefined]>(err => {
      if (errorExt) {
        Object.assign(err, errorExt);
      }
      return [err, undefined];
    });
}

type PromiseFactory<T> = () => Promise<T>;

/**
 * 创建一个处理并发请求的 Promise 队列管理器
 *
 * 该管理器确保多个 Promise 请求按顺序处理，只有第一次请求会被真正发起，
 * 其他的请求将等待第一次请求完成后，获取相同的结果。
 *
 * 主要工作机制：
 * 1. **请求入队**: 使用 `enqueuePromise` 方法将 Promise 请求添加到队列中。
 * 2. **确保单次请求**: 只有第一个请求会被真正发起，其它请求将等待第一个请求完成并共享结果。
 * 3. **结果广播**: 第一个请求的结果会被广播给所有等待的回调。
 *
 * @returns {Function} 返回一个函数，用于将 Promise 请求加入队列并确保它们共享第一个请求的结果
 */
export function createPromiseQueueManager<T = void>(): ((
  promiseFactory: PromiseFactory<T>
) => Promise<T>) {
  let isPending = false; // 标记是否正在处理请求
  const callbackList: {
    resolve: (value: T) => void
    reject: (reason?: any) => void
  }[] = []; // 等待的回调队列

  const handleResolve = (value: T) => {
    callbackList.forEach(({ resolve }) => resolve(value));
    callbackList.length = 0; // 清空队列
  };

  const handleReject = (reason?: any) => {
    callbackList.forEach(({ reject }) => reject(reason));
    callbackList.length = 0; // 清空队列
  };

  /**
   * 处理并发请求
   *
   * 只有第一次请求会真正发起，后续请求将等待第一次请求完成并共享结果。
   *
   * @param promiseFactory - 返回 Promise 的工厂函数
   * @returns {Promise<T>} 处理后的 Promise
   */
  const enqueuePromise = (promiseFactory: PromiseFactory<T>): Promise<T> => {
    return new Promise<T>((resolve, reject) => {
      // 如果请求正在处理中，添加到回调队列中
      if (isPending) {
        callbackList.push({ resolve, reject });
      }
      else {
        isPending = true;

        promiseFactory()
          .then(result => {
            handleResolve(result);
            resolve(result);
          })
          .catch(error => {
            handleReject(error);
            reject(error);
          })
          .finally(async () => {
            isPending = false; // 标记为未处理状态

            // 如果队列中还有待处理的请求，则继续处理
            if (callbackList.length > 0) {
              // 使用队列中第一个请求的 promiseFactory 进行处理
              await enqueuePromise(() => promiseFactory());
            }
          });
      }
    });
  };

  return enqueuePromise;
}

/**
 * 保证 promise 在指定时间后再返回
 * @param input 原始 promise
 * @param delay 最少等待的时间（毫秒）
 */
export function ensureDelay<T>(input: T | Promise<T>, delay: number): Promise<T> {
  return new Promise((resolve, reject) => {
    const start = Date.now();
    Promise.resolve(input)
      .then(res => {
        const elapsed = Date.now() - start;
        const wait = Math.max(0, delay - elapsed);
        setTimeout(() => resolve(res), wait);
      })
      .catch(err => {
        const elapsed = Date.now() - start;
        const wait = Math.max(0, delay - elapsed);
        setTimeout(() => reject(err), wait);
      });
  });
}
